﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Azure.Online.Proxy.Server {
    public class HttpServer {
        private readonly int _port;
        private Socket _socket;

        private Thread _thread;
        private bool _shutdown = false;

        private readonly Queue<Socket> _pending = new Queue<Socket>();
        private readonly Semaphore _semaphore = new Semaphore(0, int.MaxValue);

        public HttpServer(int port) {
            _port = port;
            for (var i = 0; i < 10; i++) {
                var thread = new Thread(WorkerEntryPoint);
                thread.Start();
            }
        }

        private void WorkerEntryPoint() {
            while (!_shutdown) {
                _semaphore.WaitOne();
                Socket clientSocket = null;
                try {
                    clientSocket = _pending.Dequeue();
                    var context = new HttpServerContext(clientSocket);
                    OnRequestReceived(new HttpServerEventArgs(context));
                } catch {
                }

                //TODO: if keep alive. put back to queue

                if (clientSocket != null) {
                    try {
                        clientSocket.Shutdown(SocketShutdown.Both);
                        clientSocket.Close();
                    } catch {
                    }
                }
            }
        }

        public void Start() {
            _shutdown = false;
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            _socket.Bind(new IPEndPoint(IPAddress.Any, _port));
            _socket.Listen(10);

            _thread = new Thread(() => {
                while (!_shutdown) {
                    var clientSocket = _socket.Accept();
                    _pending.Enqueue(clientSocket);
                    _semaphore.Release(1);
                }
            });
            _thread.Start();
        }

        public void Stop() {
            _shutdown = true;

            try {
                _socket.Shutdown(SocketShutdown.Both);
            } catch {
            }

            try {
                _socket.Close();
            } catch {
            }

            try {
                if (Thread.CurrentThread != _thread) {
                    _thread.Abort();
                }
            } catch {
            }
        }

        protected virtual void OnRequestReceived(HttpServerEventArgs args) {
            var handler = Request;
            if (handler != null) {
                handler(this, args);
            }
        }

        public event EventHandler<HttpServerEventArgs> Request;

    }
}
